package com.sq.partner.manager.sso.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.jasig.cas.client.authentication.AuthenticationFilter;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.util.AbstractConfigurationFilter;
import org.jasig.cas.client.util.AssertionThreadLocalFilter;
import org.jasig.cas.client.util.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter;

import com.sq.partner.manager.common.Config;
import com.sq.partner.manager.common.Constants;
import com.sq.partner.manager.common.GatewayCache;
import com.sq.partner.manager.util.LogUtil;
import com.sq.partner.manager.util.StrUtil;

/**
 * 单点登陆验证
 */
public class SSOFilter extends AbstractConfigurationFilter {
	private static Logger logger = LogUtil.getLog(SSOFilter.class);
	private  List<Pattern> resourcePatterns = new ArrayList<Pattern>();
	private String loginPath = null;
	private String showLoginPath = null;
	private Filter[] ssofilters = {new SingleSignOutFilter(),new AuthenticationFilter(),
			new Cas20ProxyReceivingTicketValidationFilter(),new AssertionThreadLocalFilter(),
			new HttpServletRequestWrapperFilter(),new SSOUserAdapterFilter()};
	private Filter[] umfilters = {new ManagerLoginFilter()};
	
	/**
	 * 初使化SSO配置
	 */
	public void init(FilterConfig filterConfig) throws ServletException {
		String resourcePath = filterConfig.getInitParameter("resourcePath");
		logger.info("不过滤路径:\n"+resourcePath);
		if(resourcePath != null){
			String[] paths = resourcePath.split(",");
			for(String s : paths){
				resourcePatterns.add(str2Pattern(s));
			}
		}
		
		loginPath = filterConfig.getInitParameter("loginPath");
		showLoginPath = filterConfig.getInitParameter("showLoginPath");
		
		if(ssofilters != null){
			for(Filter f : ssofilters){
				f.init(filterConfig);
			}
		}
		
		if(umfilters != null){
			for(Filter f : umfilters){
				f.init(filterConfig);
			}
		}
	}
	
	/**
	 * 根据不同配置，调用不同验证方式
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest)request;
		HttpServletResponse res = (HttpServletResponse)response;
		/* ------- 日志信息----------   */
		String uri = req.getRequestURI();
		String path = req.getContextPath();
		String uriNoPath = uri.replaceFirst(path, "");
		String qString = req.getQueryString();
		String requestUrl = uri + (qString == null ? "" : "?" +  qString );
		Long time1 = System.currentTimeMillis();
		if(uriNoPath.indexOf(";") != -1){
			uriNoPath = uriNoPath.substring(0,uriNoPath.indexOf(";"));
		}
		
		if("/".equals(uriNoPath) || StrUtil.isEmpty(uriNoPath)){
			res.sendRedirect(path + "/showIndex");
			return;
		}
		/* ------- 日志信息 end----------   */
		
//		//TODO 测试专用 测试完删除 此段代码将在后台 系统设置菜单进行刷新
//		try{
//			GatewayCache.refresh();
//		}catch(Exception e){
//			e.printStackTrace();
//		}
//		//TODO 测试专用 测试完删除 end
//		
		String switchValue = GatewayCache.getCache(Constants.LOGIN_SWITCH_VALUE);
		if(switchValue == null){
			switchValue = "1";
			logger.warn("登陆方式配置LOGIN_SWITCH_VALUE为空，默认使用1（本地登陆）");
		}
		
		if(isResource(uriNoPath) ){//不校验
			//继续filter链
			chain.doFilter(request, response);
		}else{//校验
			
			logger.info("\n");
			logger.info("开始执行:"+requestUrl);
			logger.debug("当前登陆方式:"+switchValue);
			//logger.info(uriNoPath + "需要较验");
			//读取开关
			if(Constants.SWITCH_VALUE_SSO.equals(switchValue)){//sso
				 if(uriNoPath.equals(showLoginPath)){//cas登陆 登陆页面跳到主页
					 res.sendRedirect(path+"/showIndex");
				 }else{
					 VirtualFilterChain virtualFilterChain = new VirtualFilterChain(ssofilters,chain);
					 virtualFilterChain.doFilter(request, response);
				 }
			}else{
				//登陆校验 本地和UM都用这个
				if(!uriNoPath.equals(loginPath) && !uriNoPath.equals(showLoginPath)){
					VirtualFilterChain virtualFilterChain = new VirtualFilterChain(umfilters,chain);
					virtualFilterChain.doFilter(request, response);
				}else{
					chain.doFilter(request, response);
				}
			}
			logger.info("请求["+uriNoPath+"] 执行时间:"+ (System.currentTimeMillis() - time1));
			logger.info("完成执行:"+requestUrl);
		}
		
	}
	
	/**
	 * 调用所有filter的destory方法
	 */
	public void destroy() {
		if(ssofilters != null){
			for(Filter f : ssofilters){
				f.destroy();
			}
		}
		
		if(umfilters != null){
			for(Filter f : umfilters){
				f.destroy();
			}
		}
		
	}
	
	/**
	 * 是否资源文件路径 这种路径不过滤
	 * @return
	 */
	private boolean isResource(String uri){
		if(uri == null){
			return false;
		}
		
		if(!resourcePatterns.isEmpty()){
			for(Pattern p : resourcePatterns){
				if(p.matcher(uri).matches()){
					return true;
				}
			}
		}
		return false;
	}
	
	/**
	 * filter验证失败后续处理 
	 * @param req
	 * @param res
	 * @param msg 失败提示信息
	 * @throws IOException
	 * @throws ServletException
	 */
	public static void doLoginError(HttpServletRequest req,HttpServletResponse res,String msg) throws IOException, ServletException{
		logger.error(msg);
		String accept = req.getHeader("accept");
		String contentType = req.getContentType();
		String headRequestWidth = req.getHeader("X-Requested-With");
		String path = req.getContextPath();
		String opreateName = "";
		String uri = req.getRequestURI();
		if(uri != null){
			int idx = uri.lastIndexOf("/");
			if(idx != -1){
				opreateName = uri.substring(idx).replace("/","");
			}else{
				opreateName = uri;
			}
		}
		String dispatchUri = (String)req.getAttribute("dispatchUri");
		//ajax json处理
		if((accept != null && accept.indexOf("application/json") != -1 ) || (contentType != null && contentType.indexOf("application/json") != -1 )){
			res.setContentType("application/json;charset=UTF-8");
            PrintWriter writer = res.getWriter();
            String resultMsg = "{\"result\":\"error\",\"message\":\"" + msg + "\"}";
            writer.write(resultMsg);
            writer.close();
        }else if(StrUtil.isNotEmpty(dispatchUri)){
        	req.setAttribute("javax.servlet.error.message",msg);
        	req.setAttribute("url",path);
            req.getRequestDispatcher(dispatchUri).forward(req, res);
        }
		else if("XMLHttpRequest".equalsIgnoreCase(headRequestWidth)){//ajax请求返回小页面
        	req.setAttribute("javax.servlet.error.message",msg);
        	req.setAttribute("url",path);
            req.getRequestDispatcher("/common/error").forward(req, res);
        }else{//一般请求转发
        	if(StrUtil.isEmpty(opreateName)||"showIndex".equals(opreateName)){//从主页跳过去的不提示
        		res.sendRedirect(path+"/showLogin");
        	}else{
        		res.sendRedirect(path+"/showLogin?errorcode=1");
        	}
        }
	}
	
	/**
	 * String 转成正则 目前只转*为 .*
	 * @param s
	 * @return
	 */
	public static Pattern str2Pattern(String s){
		if(s == null){
			return null;
		}
		
		Pattern p = Pattern.compile("^"+ s.replaceAll("\\*+", ".*"));
		return p;
	}
	
	/**
	 * 自定义filterChain 只执行当前filter中定义的子filter
	 * @author sankun
	 *
	 */
	private class VirtualFilterChain implements FilterChain {
		private Filter[] additionalFilters;
		private int currentPosition = 0;
		private FilterChain parentChain;

		public VirtualFilterChain(Filter[] additionalFilters,FilterChain parentChain) {
			this.additionalFilters = additionalFilters;
			this.parentChain = parentChain;
		}

		public void doFilter(ServletRequest request, ServletResponse response)
				throws IOException, ServletException {
			if (additionalFilters != null && currentPosition < additionalFilters.length) {
				currentPosition++;
				additionalFilters[currentPosition - 1].doFilter(request,response,this);
			}else{
				parentChain.doFilter(request, response);//外部继续
			}
		}
	}

}
